package main;

import java.util.LinkedList;

public class MemoryUnit extends Main {
	
	static Order Cycles = new Order(0);
	static boolean beginFetch = false;
	static int ICycles;
	static Integer result;
	static LinkedList<Instruction> inst = new LinkedList<Instruction>();
	static LinkedList<Instruction> finst = new LinkedList<Instruction>();
	
	public static void execute() {
		
		if(inst.isEmpty()) return;
		
		Instruction i = inst.getFirst();
		
		if(!i.inExecution) {
			
			i.inExecution = true;
						
			return;
		}
		if(i.N == 0){
			
			Cycles.value = 1;
		
		if(i.type.equals("LW")) {
			result = (Integer)CacheEntry.readFromCache((i.v1+i.immediate)/2, true);
		}
		
		else {
			
			CacheEntry.writeToCache((i.v2+i.immediate)/2, i.v1, 1, true);
		
		}
		
		}
		
		i.N++;
		
		if(i.N == Cycles.value) {broadCastResult();} 
		
		
	}

	static void broadCastResult() {
		
		Instruction ins = inst.removeFirst();
		
		if(!inst.isEmpty()) inst.getFirst().inExecution = true;
				
		ResStationEntry e2 = null;
		
		int physicalReg = (ins.dest);
		int robIndex = -1;
		if(physicalReg != -1) robIndex = RegRobMapping.get(ins.dest).value;
				
		for(int i=0; i<ReservationSation.size(); i++) {
			
			ResStationEntry e = ReservationSation.get(i);
			if(e.inst == ins) e2 = e;		
			
			if(e.inst.source1 == physicalReg) {
				
				e.r1 = true;
				e.v1 = result;
				e.inst.v1 = result;
			}
			
			if(e.inst.source2 == physicalReg) {
				
				e.r2 = true;
				e.v2 = result;
				e.inst.v2 = result;
			}
			
			
		}
		
		//Write in ROB
		if(physicalReg != -1) {
		ROB.get(robIndex).value = result;
		Execute.stageInstructions.add(ins);
		}
		ReservationSation.remove(e2);
		reserve--;
		if(ins.type.equals("SW")) {
			ins.finished = true;
			ins.finish = cycles_spanned;
			ins.noOfCycles++;
		}
		
	}
	
	public static void initialiazeMemory() {
	
		Cycles = new Order(0);
		
		DataMemory.put(40, 100);
		DataMemory.put(41, 101);
		DataMemory.put(42, 102);
		DataMemory.put(43, 103);
		DataMemory.put(44, 104);
		DataMemory.put(45, 105);
		DataMemory.put(46, 106);
		DataMemory.put(47, 107);
		DataMemory.put(43, 103);
		DataMemory.put(0, 25);
		
		S[0] = 128;
		l[0] = 4;
		C[0] = S[0]/l[0];
		m[0] = 4;
		
		S[1] = 256;
		l[1] = 8;
		C[1] = S[1]/l[1];
		m[1] = 2;
		
		S[2] = 512;
		l[2] = 16;
		C[2] = S[2]/l[2];
		m[2] = 2;
		
		n_cache_levels = 3;
		
		CacheEntry.initializeCaches();
		
		writingPolicy_hit[0] = false;
		writingPolicy_hit[1] = false;
		writingPolicy_hit[2] = false;
		
		writingPolicy_miss[0] = false;
		writingPolicy_miss[1] = !true;
		writingPolicy_miss[2] = !true;
		
		n_data_mem = 3;
		cache_cycles[0] = 1;
		cache_cycles[1] = 1;
		cache_cycles[2] = 2;
		
	}
	
	public static boolean fecthFromMemory() {
		
		if(!beginFetch){
		
		ICycles = CacheEntry.getCyclesICache(PC, 
				Math.min(ways, Math.min(END-PC, ib_size-inst_buffer.size())));
		
		//System.out.println(ICycles+"YARARAAAAB"+n_data_mem);
				
		for(int j=0; j<ways && PC < END; j++) {
			
			if(ib_size == inst_buffer.size()) break;
			
			Instruction ins = ((Instruction)CacheEntry.readFromCache(PC++, false)).clone();
			ins.turn = PC - 1;
			finst.add(ins);
			}
			
			ICycles = ICycles>=1?(ICycles-1):0;
			beginFetch = true;
		
		}
		
		if(beginFetch) {
			if(ICycles == 0) {
			beginFetch = false; 
			return true;
			}
			ICycles--;
			return false;
		}
		
		return true;
		
		
	}
	

}
